package com.shareyi.wox.core.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.shareyi.wox.config.ActionBean;
import com.shareyi.wox.config.InterceptorRef;
import com.shareyi.wox.config.ResultBean;
import com.shareyi.wox.config.ResultTypeBean;
import com.shareyi.wox.config.WoxConstant;
import com.shareyi.wox.context.ActionContext;
import com.shareyi.wox.core.ActionInvocation;
import com.shareyi.wox.core.ActionProxy;
import com.shareyi.wox.core.Configuration;
import com.shareyi.wox.core.ObjectFactory;
import com.shareyi.wox.core.WoxConfiguartion;
import com.shareyi.wox.core.WoxException;
import com.shareyi.wox.core.interceptor.Interceptor;
import com.shareyi.wox.result.WoxResultSupport;
import com.shareyi.wox.util.MatchHelper;

public class DefaultActionInvocation implements ActionInvocation {

	
	 private static final Log log = LogFactory.getLog(DefaultActionInvocation.class);
	    protected ActionProxy proxy;
	    protected Map<String, Object> extraContext;
	    protected ActionContext invocationContext;
	    protected WoxResultSupport result;
	    protected String resultCode;
	    protected boolean executed = false;
	    protected boolean pushAction = true;
	    protected ObjectFactory objectFactory;
	    private  WoxConfiguartion woxConfiguartion;
	    private Iterator<InterceptorRef> interceptorRefs;
	    private Configuration configuration;
	

	public boolean isExecuted() {
		return executed;
	}

	public ActionProxy getProxy() {
		return proxy;
	}

	public WoxResultSupport getResult() throws Exception {
		return result;
	}

	public String getResultCode() {
		return resultCode;
	}

	public void setResultCode(String resultCode) {
		this.resultCode=resultCode;
	}

	public String invoke() throws Exception {
		if(interceptorRefs.hasNext()){
			InterceptorRef interceptorRef=interceptorRefs.next();
			Interceptor interceptor=interceptorRef.getInterceptor();
			if(interceptor==null){
			 interceptor=objectFactory.buildInterceptor(interceptorRef);
			 interceptorRef.setInterceptor(interceptor);
			}
			resultCode= interceptor.intercept(this);
		}else{
			resultCode= proxy.execute();
			executed=true;
		}
		return resultCode;
	}

	public String invokeActionOnly() throws Exception {
		resultCode= proxy.execute();
		executed=true;
		return resultCode;
	}

	public void init(WoxConfiguartion woxConfiguartion,Configuration configuration) throws Exception {
			this.configuration=configuration;
			this.objectFactory=woxConfiguartion.getObjectFactory();
			this.invocationContext = ActionContext.getContext();
	        if (invocationContext != null) {
	        	invocationContext.setActionInvocation(this);
	        }

	        createAction();
	        List<InterceptorRef> interceptorRefList = new ArrayList<InterceptorRef>(proxy.getConfig().getInterceptors());
	        interceptorRefs = interceptorRefList.iterator();
	}

	private void createAction() throws Exception {
		DefaultActionProxy actionProxy=new DefaultActionProxy(this, configuration.getNamespace(),
				configuration.getActionName(), configuration.getMethodName(), false, false);
		this.proxy=actionProxy;
		
		actionProxy.setConfiguration(configuration);
		actionProxy.setObjectFactory(objectFactory);
		actionProxy.prepare();
		
	}

	public ActionBean getActionBean() {
		return configuration.getActionBean();
	}

			

	public void finishInvoke() throws Exception {
		
		
		
		ResultBean resultBean=configuration.getActionBean().getResultBeanByCodeAndPatternMap(resultCode,configuration.getPatternResult());
		if(resultBean==null){
			throw new WoxException("not result found for ["+resultCode+"] in action :"+configuration.getActionName());
		}
		
		ResultTypeBean resultTypeBean=configuration.getPackageBean().getResultTypeByName(resultBean.getType());
		if(resultTypeBean==null){
			throw new WoxException("not result type found for ["+resultBean.getType()+"]");
		}
		result=objectFactory.buildResult(resultTypeBean, extraContext);
		
		String finalLocation=MatchHelper.resultUrlMatcher(resultBean.getPath(), configuration.getPatternResult(), invocationContext.getValueContext().getContext());
		result.setLocation(finalLocation);
	}

}
